#ifndef RP2IMAGE_H
#define RP2IMAGE_H

#include "Rp2Object.h"
#include "Rp2ColorRGBA.h"

namespace Rp2
{
class Image : public Object 
{
	RP2_DECLARE_RTTI;
	RP2_DECLARE_NAME_ID;
	RP2_DECLARE_INITIALIZE;
	RP2_DECLARE_TERMINATE;

public:

    enum FormatMode
    {
        IT_RGB888,
        IT_RGBA8888,
        IT_DEPTH16,
        IT_DEPTH24,
        IT_DEPTH32,
        IT_CUBE_RGB888,
        IT_CUBE_RGBA8888,
        IT_RGB32F,
        IT_RGBA32F,
        IT_RGB16F,
        IT_RGBA16F,
        IT_RGB16I,
        IT_RGBA16I,
        IT_INTENSITY8I,
        IT_INTENSITY16I,
        IT_INTENSITY16F,
        IT_INTENSITY32F,
        IT_RGB565,   // (high)   B G R (low)
        IT_RGBA5551, // (high) A B G R (low)
        IT_RGBA4444, // (high) A B G R (low)
		IT_BGR888,
		IT_BGRA8888,
        IT_QUANTITY
    };

	enum ImageFormat
	{
		IF_WMIF,
		IF_TGA,
		IF_QUANTITY
	};

    // Construction and destruction.  Image accepts responsibility for
    // deleting the input array.  The acImageName field is required and
    // is used as a unique identifier for the image for purposes of sharing.

    // 1D image
    Image (FormatMode eFormat, int iBound0, unsigned char* aucData,
        const char* acImageName);

    // 2D image
    Image (FormatMode eFormat, int iBound0, int iBound1,
        unsigned char* aucData, const char* acImageName);

    // 3D image
    Image (FormatMode eFormat, int iBound0, int iBound1, int iBound2,
        unsigned char* aucData, const char* acImageName);

    virtual ~Image ();

    // Member access.
    FormatMode GetFormat () const;
    const std::string& GetFormatName () const;
    static std::string GetFormatName (int eFormat);
    bool IsDepthImage () const;
    bool IsCubeImage () const;
    int GetBytesPerPixel () const;
    static int GetBytesPerPixel (int eFormat);
    int GetDimension () const;
    int GetBound (int i) const;
    int GetQuantity () const;
    unsigned char* GetData () const;
    unsigned char* operator() (int i);

    // Deferred allocation of image data.
    void AllocateData ();

    // Streaming support.  The sharing system is automatically invoked by
    // these calls.  In Load, if an image corresponding to the filename is
    // already in memory, then that image is returned (i.e. shared).
    // Otherwise, a new image is created and returned.  The filename is used
    // as the image name.
    static Image* Load (const std::string &rkImageName);
	static Image* OnLoad(ImageFormat eIFormat, const char* rkDecorated,
		const std::string& rkFilename);
	static ImageFormat GetImageFormat (const std::string& rkImageName);

	// image load factory
	static Image* LoadImageWMIF(const char* rkDecorated,
		const std::string& rkFilename);
	static Image* LoadImageTGA(const char* rkDecorated,
		const std::string& rkFilename);

    // This is intended to support saving procedurally generated images or
    // for utilities that convert to WMIF from another format.  The filename
    // in this call does not replace the image name that might already exist.
    bool Save (const char* acFilename);

	// Create an image of ColorRGBA values.  The function returns an image
    // of the same width and height for these formats.  The returned image
    // is dynamically allocated; the caller is responsible for deleting it.
    ColorRGBA* CreateRGBA () const;

    // Copy to an already existing image of ColorRGBA values.  The input
    // array must have the correct dimensions as the Image itself.
    void CopyRGBA (ColorRGBA* akCImage) const;

protected:
    // support for streaming
    Image ();

    FormatMode m_eFormat;
    int m_iDimension;
    int m_aiBound[3];
    int m_iQuantity;
    unsigned char* m_aucData;

    static int ms_aiBytesPerPixel[IT_QUANTITY];
    static std::string ms_akFormatName[IT_QUANTITY];
	// map for image format name
	static std::string ms_kIFStringMap[IF_QUANTITY];
	static std::map<std::string, ImageFormat>* ms_pkFormatMap;
};

RP2_REGISTER_INITIALIZE(Image);
RP2_REGISTER_TERMINATE(Image);
typedef Pointer<Image> ImagePtr;
#include "Rp2Image.inl"

}

#endif